import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_rtmp/flutter_rtmp.dart';

enum StreamStatus { noConnected, connecting, connected }

class RtmpPage extends StatefulWidget {
  const RtmpPage({this.rtmpUrl, Key key}) : super(key: key);
  final String rtmpUrl;
  @override
  _RtmpPageState createState() => _RtmpPageState();
}

class _RtmpPageState extends State<RtmpPage> {
  CameraController controller;
  List<CameraDescription> cameras = [];
  bool isFullScreen = true;
  StreamStatus streamStatus = StreamStatus.noConnected;
  int hasChoicedCamerasIndex;
  String url;
  Timer _timer;

  @override
  void initState() {
    getCamerasList();
    super.initState();
  }

  @override
  void dispose() {
    if (controller != null) {
      controller.dispose();
    }
    if (_timer != null) {
      _timer.cancel();
      _timer = null;
    }
    super.dispose();
  }

  void initController(CameraDescription cameraDescription) async {
    if (controller != null) {
      await controller.dispose();
    }
    controller = CameraController(
      cameraDescription,
      ResolutionPreset.high,
      enableAudio: true,
      androidUseOpenGL: true,
    );

    // If the controller is updated then update the UI.
    controller.addListener(() {
      if (mounted) setState(() {});
      if (controller.value.hasError) {
        // showInSnackBar('Camera error ${controller.value.errorDescription}');
        if (_timer != null) {
          _timer.cancel();
          _timer = null;
        }
        // Wakelock.disable();
      }
      if (controller.value.hasEventType) {
        switch (controller.value.eventType) {
          case 'error':
            streamStatus = StreamStatus.noConnected;
            showAlert(controller.value.errorDescription);
            break;
          case 'camera_closing':
            // streamStatus = StreamStatus.noConnected;
            break;
          case 'rtmp_connected':
            streamStatus = StreamStatus.connected;
            break;
          case 'rtmp_retry':
            streamStatus = StreamStatus.connecting;
            break;
          case 'rtmp_stopped':
            streamStatus = StreamStatus.noConnected;
            showAlert('连接失败');
            break;
          case 'rotation_update':
            break;
        }
        setState(() {});
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      _showCameraException(e);
    }

    if (mounted) {
      setState(() {});
    }
  }

  void _showCameraException(CameraException e) {
    logError(e.code, e.description);
    // showInSnackBar('Error: ${e.code}\n${e.description}');
  }

  void getCamerasList() async {
    try {
      cameras = await availableCameras();
      print(cameras);
      if (cameras.length > 0) {
        List array = cameras;
        for (var i = 0; i < cameras.length; i++) {
          CameraDescription cameraDescription = cameras[i];
          print(cameraDescription.lensDirection);
          if (cameraDescription.lensDirection == CameraLensDirection.front) {
            array.removeAt(i);
            array.insert(0, cameraDescription);
            break;
          }
        }
        cameras = array;
        hasChoicedCamerasIndex = 0;
        initController(cameras[0]);
      }
    } on CameraException catch (e) {
      logError(e.code, e.description);
    }
  }

  void logError(String code, String message) =>
      print('Error: $code\nError Message: $message');

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      backgroundColor: Color(0x000000),
      child: Stack(
        fit: StackFit.expand,
        children: [
          Container(
            child: cameras.length == 0
                ? Center(child: new Text("启用设备中"))
                : Padding(
                    padding: const EdgeInsets.all(0.0),
                    child: Center(
                      child: _cameraPreviewWidget(),
                    ),
                  ),
          ),
          _clarifyButtonWidget(),
          _switchCameraWidget(),
          _startRtmpWidget(),
          streamStatus == StreamStatus.connecting
              ? LoadingDialog()
              : SizedBox(),
          _closeRtmpWidget(),
        ],
      ),
    );
  }

  void showClarity() async {
    List<Widget> array = [];
    ResolutionPreset.values.forEach((element) {
      array.add(CupertinoActionSheetAction(
        child: Text(getClarifyName(element)),
        onPressed: () {
          Navigator.of(context).pop(element);
          print(element);
          controller.resetResolutionPreset(element);
          setState(() {});
        },
        isDefaultAction: true,
      ));
    });

    var result = await showCupertinoModalPopup(
        context: context,
        builder: (context) {
          return CupertinoActionSheet(
            title: Text(''),
            message: Text('请选择清晰度？'),
            actions: array,
            cancelButton: CupertinoActionSheetAction(
              child: Text('取消'),
              onPressed: () {
                Navigator.of(context).pop('cancel');
              },
            ),
          );
        });
    print('$result');
  }

  String getClarifyName(ResolutionPreset clarify) {
    String clarifyName = '高';
    switch (clarify) {
      case ResolutionPreset.low:
        clarifyName = '低';
        break;
      case ResolutionPreset.medium:
        clarifyName = '中';
        break;
      case ResolutionPreset.high:
        clarifyName = '高';
        break;
      case ResolutionPreset.veryHigh:
        clarifyName = '高清';
        break;
      case ResolutionPreset.ultraHigh:
        clarifyName = '超高清';
        break;
      case ResolutionPreset.max:
        clarifyName = '最大';
        break;
      default:
    }
    return clarifyName;
  }

  Widget _cameraPreviewWidget() {
    if (controller == null || !controller.value.isInitialized) {
      return const Text(
        'Tap a camera',
        style: TextStyle(
          color: Color(0xffffff),
          fontSize: 24.0,
          fontWeight: FontWeight.w900,
        ),
      );
    } else {
      // final size = MediaQuery.of(context).size;
      // final width = size.width;
      // final height = size.height;
      return AspectRatio(
        aspectRatio: controller.value.aspectRatio,
        child: CameraPreview(controller),
      );
    }
  }

  void showCameraList() async {
    if (cameras.length <= 1) {
      print("暂无其余可用摄像头");
      return;
    } else if (cameras.length == 2) {
      print("直接切换摄像头");
      if (hasChoicedCamerasIndex == 0) {
        switchCamera(cameras[1]);
        hasChoicedCamerasIndex = 1;
      } else {
        switchCamera(cameras[0]);
        hasChoicedCamerasIndex = 0;
      }
      return;
    }
    List<Widget> array = [];
    cameras.forEach((element) {
      array.add(CupertinoActionSheetAction(
        child: Text(getCameraName(element)),
        onPressed: () {
          Navigator.of(context).pop(element);
          print(element);
          switchCamera(element);
          setState(() {});
        },
        isDefaultAction: true,
      ));
    });

    var result = await showCupertinoModalPopup(
        context: context,
        builder: (context) {
          return CupertinoActionSheet(
            title: Text(''),
            message: Text('请选择摄像头？'),
            actions: array,
            cancelButton: CupertinoActionSheetAction(
              child: Text('取消'),
              onPressed: () {
                Navigator.of(context).pop('cancel');
              },
            ),
          );
        });
    print('$result');
  }

  void switchCamera(CameraDescription cameraDescription) {
    if (_timer != null) {
      _timer.cancel();
      _timer = null;
    }

    if (streamStatus == StreamStatus.noConnected) {
      controller.switchCamera(cameraDescription);
    } else {
      controller.switchCamera(cameraDescription);
    }
    // _timer = Timer.periodic(Duration(seconds: 1), (timer) async {
    //   var stats = await controller.getStreamStatistics();
    //   print(stats);
    // });
  }

  String getCameraName(CameraDescription camera) {
    String name = '';
    switch (camera.lensDirection) {
      case CameraLensDirection.front:
        name = '前置';
        break;
      case CameraLensDirection.back:
        name = '后置';
        break;
      case CameraLensDirection.external:
        name = '外接';
        break;
      default:
    }
    return name;
  }

  Widget _closeRtmpWidget() {
    return Positioned(
      top: 80.0,
      left: 20,
      width: 60,
      height: 30,
      child: CupertinoButton(
          padding: EdgeInsets.all(0),
          child: Text("关闭",
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.white,
              )),
          color: Colors.blue,
          borderRadius: BorderRadius.all(Radius.circular(15)),
          // onPressed: streamStatus == StreamStatus.noConnected
          //     ? () => {showClarity()}
          //     : () => {print("test")}),
          onPressed: () => {closepage()}),
    );
  }

  void closepage() {
    if (controller.value.isStreamingVideoRtmp) {
      controller.stopVideoStreaming();
    }
    controller.dispose();
    Navigator.pop(context);
  }

  Widget _clarifyButtonWidget() {
    return Positioned(
      top: 30.0,
      left: 20,
      width: 60,
      height: 30,
      child: CupertinoButton(
          padding: EdgeInsets.all(0),
          child: Text("清晰度",
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.white,
              )),
          color: Colors.blue,
          borderRadius: BorderRadius.all(Radius.circular(15)),
          // onPressed: streamStatus == StreamStatus.noConnected
          //     ? () => {showClarity()}
          //     : () => {print("test")}),
          onPressed: () => {showClarity()}),
    );
  }

  Widget _switchCameraWidget() {
    return Positioned(
      top: 30.0,
      left: 120,
      width: 100,
      height: 30,
      child: CupertinoButton(
          padding: EdgeInsets.all(0),
          child: Text("切换摄像头",
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.white,
              )),
          color: Colors.blue,
          borderRadius: BorderRadius.all(Radius.circular(15)),
          // onPressed: streamStatus == StreamStatus.noConnected
          //     ? () => {showCameraList()}
          //     : () => {print("test")}),
          onPressed: () => {showCameraList()}),
    );
  }

  Widget _startRtmpWidget() {
    return Positioned(
      top: 30.0,
      left: 250,
      width: 100,
      height: 30,
      child: CupertinoButton(
          padding: EdgeInsets.all(0),
          child: Text(streamStatus == StreamStatus.connected ? "停止" : "开始直播",
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.white,
              )),
          color: Colors.blue,
          borderRadius: BorderRadius.all(Radius.circular(15)),
          onPressed: streamStatus == StreamStatus.noConnected
              ? () => {
                    startVideoStreaming()
                        .then((url) => {if (mounted) setState(() {})})
                  }
              : () => {pressstopVideoStreaming()}),
    );
  }

  void pressstopVideoStreaming() async {
    await stopVideoStreaming();
    streamStatus = StreamStatus.noConnected;
    setState(() {});
  }

  Future<String> startVideoStreaming() async {
    if (!controller.value.isInitialized) {
      showAlert('Error: select a camera first.');
      return null;
    }

    // if (controller.value.isStreamingVideoRtmp) {
    //   showAlert('正在直播.');
    //   return null;
    // }
    if (streamStatus == StreamStatus.connected) {
      showAlert('正在直播.');
      return null;
    }

    // Open up a dialog for the url
    String myUrl = widget.rtmpUrl;

    try {
      if (_timer != null) {
        _timer.cancel();
        _timer = null;
      }
      url = myUrl;
      streamStatus = StreamStatus.connecting;
      setState(() {});
      await controller.startVideoStreaming(url);
      _timer = Timer.periodic(Duration(seconds: 1), (timer) async {
        var stats = await controller.getStreamStatistics();
        print(stats);
      });
    } on CameraException catch (e) {
      _showCameraException(e);
      return null;
    }
    return url;
  }

  Future<void> stopVideoStreaming() async {
    if (!controller.value.isStreamingVideoRtmp) {
      return null;
    }

    try {
      await controller.stopVideoStreaming();
      if (_timer != null) {
        _timer.cancel();
        _timer = null;
      }
    } on CameraException catch (e) {
      _showCameraException(e);
      return null;
    }
  }

  Future<void> pauseVideoStreaming() async {
    if (!controller.value.isStreamingVideoRtmp) {
      return null;
    }

    try {
      await controller.pauseVideoStreaming();
      streamStatus = StreamStatus.noConnected;
      setState(() {});
    } on CameraException catch (e) {
      _showCameraException(e);
      rethrow;
    }
  }

  Future<void> resumeVideoStreaming() async {
    if (!controller.value.isStreamingVideoRtmp) {
      return null;
    }

    try {
      await controller.resumeVideoStreaming();
    } on CameraException catch (e) {
      _showCameraException(e);
      rethrow;
    }
  }

  void showAlert(String message) async {
    // await showCupertinoModalPopup(
    //     context: context,
    //     builder: (context) {
    //       return CupertinoAlertDialog(
    //         content: Text(message),
    //       );
    //     });

    // Timer(Duration(seconds: 2), () {
    //   //到时回调
    //   print('afterTimer=' + DateTime.now().toString());
    // });
    RToast.toast(context, msg: message);
  }
}

//Toast 显示位置控制
enum ToastPostion {
  top,
  center,
  bottom,
}

class RToast {
  // toast靠它加到屏幕上
  static OverlayEntry _overlayEntry;
  // toast是否正在showing
  static bool _showing = false;
  // 开启一个新toast的当前时间，用于对比是否已经展示了足够时间
  static DateTime _startedTime;
  // 提示内容
  static String _msg;
  // toast显示时间
  static int _showTime;
  // 背景颜色
  static Color _bgColor;
  // 文本颜色
  static Color _textColor;
  // 文字大小
  static double _textSize;
  // 显示位置
  static ToastPostion _toastPosition;
  // 左右边距
  static double _pdHorizontal;
  // 上下边距
  static double _pdVertical;
  static void toast(
    BuildContext context, {
    //显示的文本
    String msg,
    //显示的时间 单位毫秒
    int showTime = 1000,
    //显示的背景
    Color bgColor = Colors.black,
    //显示的文本颜色
    Color textColor = Colors.white,
    //显示的文字大小
    double textSize = 14.0,
    //显示的位置
    ToastPostion position = ToastPostion.center,
    //文字水平方向的内边距
    double pdHorizontal = 20.0,
    //文字垂直方向的内边距
    double pdVertical = 10.0,
  }) async {
    assert(msg != null);
    _msg = msg;
    _startedTime = DateTime.now();
    _showTime = showTime;
    _bgColor = bgColor;
    _textColor = textColor;
    _textSize = textSize;
    _toastPosition = position;
    _pdHorizontal = pdHorizontal;
    _pdVertical = pdVertical;
    //获取OverlayState
    OverlayState overlayState = Overlay.of(context);
    _showing = true;
    if (_overlayEntry == null) {
      //OverlayEntry负责构建布局
      //通过OverlayEntry将构建的布局插入到整个布局的最上层
      _overlayEntry = OverlayEntry(
          builder: (BuildContext context) => Positioned(
                //top值，可以改变这个值来改变toast在屏幕中的位置
                top: buildToastPosition(context),
                child: Container(
                    alignment: Alignment.center,
                    width: MediaQuery.of(context).size.width,
                    child: Padding(
                      padding: EdgeInsets.symmetric(horizontal: 40.0),
                      child: AnimatedOpacity(
                        opacity: _showing ? 1.0 : 0.0, //目标透明度
                        duration: _showing
                            ? Duration(milliseconds: 100)
                            : Duration(milliseconds: 400),
                        child: _buildToastWidget(),
                      ),
                    )),
              ));
      //插入到整个布局的最上层
      overlayState.insert(_overlayEntry);
    } else {
      //重新绘制UI，类似setState
      _overlayEntry.markNeedsBuild();
    }
    // 等待时间
    await Future.delayed(Duration(milliseconds: _showTime));
    //2秒后 到底消失不消失
    if (DateTime.now().difference(_startedTime).inMilliseconds >= _showTime) {
      _showing = false;
      _overlayEntry.markNeedsBuild();
      await Future.delayed(Duration(milliseconds: 400));
      _overlayEntry.remove();
      _overlayEntry = null;
    }
  }

  //toast绘制
  static _buildToastWidget() {
    return Center(
      child: Card(
        color: _bgColor,
        child: Padding(
          padding: EdgeInsets.symmetric(
              horizontal: _pdHorizontal, vertical: _pdVertical),
          child: Text(
            _msg,
            style: TextStyle(
              fontSize: _textSize,
              color: _textColor,
            ),
          ),
        ),
      ),
    );
  }

//  设置toast位置
  static buildToastPosition(context) {
    var backResult;
    if (_toastPosition == ToastPostion.top) {
      backResult = MediaQuery.of(context).size.height * 1 / 4;
    } else if (_toastPosition == ToastPostion.center) {
      backResult = MediaQuery.of(context).size.height * 2 / 5;
    } else {
      backResult = MediaQuery.of(context).size.height * 3 / 4;
    }
    return backResult;
  }
}

class LoadingDialog extends Dialog {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: new Material(
        ///背景透明
        color: Colors.transparent,

        ///保证控件居中效果
        child: new Center(
          ///弹框大小
          child: new SizedBox(
            width: 120.0,
            height: 120.0,
            child: new Container(
              ///弹框背景和圆角
              decoration: ShapeDecoration(
                color: Color(0xffffffff),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(8.0),
                  ),
                ),
              ),
              child: new Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  new CircularProgressIndicator(),
                  new Padding(
                    padding: const EdgeInsets.only(
                      top: 20.0,
                    ),
                    child: new Text(
                      "加载中",
                      style: new TextStyle(fontSize: 16.0),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}
